package stz.flash.main.flashlight.model;

import java.io.IOException;

import javax.microedition.amms.control.camera.FlashControl;
import javax.microedition.media.MediaException;
import javax.microedition.media.Player;
import javax.microedition.media.control.VideoControl;

import net.rim.device.api.system.Application;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Manager;
import net.rim.device.api.ui.container.VerticalFieldManager;
import stz.flash.Info;
import stz.flash.main.BulbField;
import stz.flash.main.FlashScreen;
import stz.flash.option.PersistentData;
import stz.flash.option.flashlight.FlashlightOption;
import util.DjObservable;
import util.DjObserver;

/**
 *  Player.stop이나 FlashControl.mode(off)등을 쓰면 에러가 속출하는데
 *  VideoField를 add/delete 하면 에러없이 작동을 잘함
 *  
 *  옵저버로 등록되어있는 클래스 
 *   @param BulbField
 */
public class Flashlight implements DjObserver{

	//OS6
	private static final String VIDEO_ENCODING_H263 = 
			"capture://video?encoding=video/3gpp&video_codec=H263";
	//OS7
	private static final String VIDEO_ENCODING_DEFAULT = 
			"capture://video?encoding=video/3gpp&";
	
	private static final int DELAY_AFTER_TREAT = 500;//50으로 했더니 충돌

	private static final Flashlight instance = new Flashlight();
	
	private static Thread thread;
	private static Field videoField;
	private static Player videoPlayer;
	private static VideoControl videoCtrl;
	private static Object lock = new Object();
	
	private static Manager videoManager;
	private static final String defaultVideoEncoding;
	private static String currentVideoEncoding;
	
	private static boolean startedFlashlight;
	
	static {
		if (Info.SOFTWARE_VERSION == 7) {
			defaultVideoEncoding = VIDEO_ENCODING_DEFAULT;
			videoManager = new VideoManager_OS7();
		} else {
			defaultVideoEncoding = VIDEO_ENCODING_H263;
			videoManager = new VideoManager_OS6();
		}
	}
	
	
	private Flashlight() {
	}

	public void update(DjObservable observable, Object obj) {
		if (FlashlightOption.isCurrentFlashState()) {
			startFlashlight();
		} else
			stopFlashlight();
		BulbField.getIns().updateBulb();
	}
	
	public static Flashlight getIns(){
		return instance;
	}
	
	public static synchronized void startFlashlight() {
	
		if (startedFlashlight)
			return;
		startedFlashlight = true;
		
		thread = new Thread(){
			public void run() {
				synchronized (lock) {
					try {
						PersistentData.getPersistentDatabase().setFlashlightThreadState(true);////

						delVideoField_And_Player_Close();
						createVideoPlayerFamily(defaultVideoEncoding);
						addVideoField();
						sleep(Integer.MAX_VALUE);

					} catch (InterruptedException e) {
					} finally{

						delVideoField_And_Player_Close();
						treatH263();//원인모를 충돌현상?이 있었을때 이라인을 지워도 여전했음
						startedFlashlight = false;
						
						PersistentData.getPersistentDatabase().setFlashlightThreadState(false);///
					}
				}
			}
		};
		thread.start();
	}
	private static void createVideoPlayerFamily(String encoding) {
		try {
			
			currentVideoEncoding = encoding;
			videoPlayer = javax.microedition.media.Manager
					.createPlayer(encoding);
			videoPlayer.realize();
			videoPlayer.start();
			
			videoCtrl = (VideoControl) videoPlayer
					.getControl("javax.microedition.media.control.VideoControl");
			videoField = (Field) videoCtrl.initDisplayMode(VideoControl.USE_GUI_PRIMITIVE,
					"net.rim.device.api.ui.Field");
			FlashControl flashCtrl = (FlashControl) videoPlayer
					.getControl("javax.microedition.amms.control.camera.FlashControl");
			flashCtrl.setMode(FlashControl.FORCE);
			
		} catch (IOException e) {
		} catch (MediaException e) {
		}
	}
	private static synchronized void addVideoField() {
	//생성자에서 videoField를 add()시키면 문제가 생겨서 여기서 add()함
		if (videoField != null && videoField.getIndex() == -1) {
			synchronized (Application.getEventLock()) {
				videoManager.add(videoField);
			}
		}
		
		if (videoManager != null && videoManager.getIndex() == -1) {
			synchronized (Application.getEventLock()) {
//				FlashScreen.getMetaManager().add(videoManager);
			}
		}
	}
	private static synchronized void delVideoField_And_Player_Close() {
		
		if (videoField != null && videoField.getIndex() != -1) {
			synchronized (Application.getEventLock()) {
				videoManager.delete(videoField);
			}
		}
		if (videoManager != null && videoManager.getIndex() != -1) {
			synchronized (Application.getEventLock()) {
//				FlashScreen.getMetaManager().delete(videoManager); 
			}
		}

		if (videoPlayer != null) {
			//DEFAULT 인코딩을 사용할때는 확실하게 종료시켜주자
			if (currentVideoEncoding == VIDEO_ENCODING_DEFAULT) {
				videoPlayer.close();
				
			//H263 코덱을 사용할때는 stop()을 해줘야 충돌이 없음
			} else if (currentVideoEncoding == VIDEO_ENCODING_H263) {
				try {
					videoPlayer.stop();
				} catch (MediaException e) {
				}
			}
		}
	}
	private static void treatH263(){
		//OS6에서만 실행됨
		if (Info.SOFTWARE_VERSION == 6) {
			
			createVideoPlayerFamily(VIDEO_ENCODING_DEFAULT);
			addVideoField();
			try {
				Thread.sleep(DELAY_AFTER_TREAT);//Delay를 줘야 충돌이 없음
			} catch (InterruptedException e) {
			}
		}
		delVideoField_And_Player_Close();
	}

	
	public static void stopFlashlight(){
		if (thread == null || thread.isAlive() == false)
			return;
		thread.interrupt();
	}
	
	public static Field getVideoManager() {
		return videoManager;
	}
	
	public static Thread getThread(){
		return thread;
	}
	
	
	/*
	 * Managers
	 */
	static class VideoManager_OS7 extends Manager {
		
		public VideoManager_OS7() {
			super(0);
		}
		
		protected void sublayout(int i, int j) {
		}
		
		public boolean isFocusable() {
			return false;
		}
	}
	
	static class VideoManager_OS6 extends VerticalFieldManager {
		
		private VideoManager_OS6() {
		}

		public boolean isFocusable() {
			return false;
		}
	}
}

